package com.tech.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.tech.model.DocModelField;
import com.tech.model.ExtFuncEntity;
import com.tech.model.GeneratorResult;
import com.tech.model.TemplateEntity;
import com.tech.repo.CommonRepo;
import com.tech.repo.ExtFuncEntityRepository;
import com.tech.repo.GlobalConfigEntityRepository;
import com.tech.repo.TemplateEntityRepository;
import com.tech.utils.DocModelFieldListener;
import freemarker.template.Template;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.tech.utils.Option.*;

/**
 * Created by zouyao on 2023/06/04
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class ExcelProcessorImpl extends Processor {

    private final TemplateEntityRepository     templateRepo;
    private final GlobalConfigEntityRepository configRepo;
    private final ExtFuncEntityRepository      extFuncRepo;
    private final CommonRepo                   commonRepo;

    @Override
    public Map<String, List<DocModelField>> readMetaData(File file) {
        DocModelFieldListener fieldListener = new DocModelFieldListener();
        EasyExcel.read(file, DocModelField.class, fieldListener).doReadAll();
        return fieldListener.getDocInfoArena();
    }

    @Override
    public List<GeneratorResult> fillInfo(Map<String, List<DocModelField>> metaData,List<TemplateEntity> templateList){

        List<GeneratorResult> resultList = new ArrayList<>();
        metaData.forEach((sheetName, sheetInfo) -> {
            GeneratorResult result = GeneratorResult.of(sheetName);
            // 循环处理模版
            for (TemplateEntity template : templateList) {
                // dto特殊处理
                if (StrUtil.contains(template.getTag(), "dto")){
                    Map<String, List<Tree<String>>> r = formatMetaData(sheetInfo);
                    List<Tuple> dtoInfoList = new ArrayList<>();
                    r.forEach( (k,v) -> {
                        Tree<String> treeNode = DocModelField.ofTree(sheetName + k);
                        treeNode.putExtra(DATA_FLOW, k);
                        treeNode.setChildren(v);
                        processDtoTree(template.asFreeMarkTemplate(),treeNode,dtoInfoList);
                    });
                    Map<String, List<Tuple>> collect = dtoInfoList.stream().collect(Collectors.groupingBy(x -> x.get(0).toString()));
                    result.getResultMap().put(template.getName(),collect);
                    break;
                }
                // 其他使用默认处理
                result.getResultMap().put(template.getName(),fillTemplate(template.asFreeMarkTemplate(), sheetInfo));
            }
            resultList.add(result);
        });

        return resultList;
    }

    /**
     * 将数据根据dataFlow转换为request/response
     * @param list
     * @return
     */
    private Map<String, List<Tree<String>>> formatMetaData(List<DocModelField> list){
        List<TreeNode<String>> nodeList = list.stream().map(x -> {
            TreeNode<String> node = new TreeNode<>(x.getIndex(), x.getParentIndex(), x.getName(), null);
            node.setExtra(BeanUtil.beanToMap(x));
            return node;
        }).collect(Collectors.toList());
        Map<String, List<TreeNode<String>>> dataFlowMap = nodeList.stream().collect(
                Collectors.groupingBy(x -> x.getExtra().get(DATA_FLOW).toString())
        );
        return dataFlowMap.entrySet().stream()
                .collect(
                        Collectors.toMap(
                                Map.Entry::getKey,
                                entry -> TreeUtil.build(entry.getValue(), ROOT_ID, treeNodeConfig,
                                        (treeNode, tree) -> {
                                            tree.setId(treeNode.getId());
                                            tree.setParentId(treeNode.getParentId());
                                            tree.setWeight(treeNode.getWeight());
                                            tree.setName(treeNode.getName());
                                            treeNode.getExtra().forEach(tree::putExtra);
                                        })
                        )
                );
    }

    /**
     * 递归处理树
     * @param treeNode
     */
    private void processDtoTree(Template freeMarkTemplate,Tree<String> treeNode, List<Tuple> list){
        if (CollectionUtil.isEmpty(treeNode.getChildren()))return;
        String s = fillTemplate(freeMarkTemplate, treeNode);
        list.add(new Tuple(treeNode.get(DATA_FLOW),treeNode.getName(),s));
        treeNode.getChildren().forEach( x -> processDtoTree(freeMarkTemplate,x, list));
    }

}
